// 四、手写实现MyPromise源码
// 要求：尽可能还原Promise中的每一个API，并通过注释的方式描述思路和原理
const isFunction = value => typeof value === 'function';
const isPromise = value => {
	if (
		(value != null && typeof value === 'object') ||
		typeof value === 'function'
	) {
		if (typeof value.then == 'function') {
			return true;
		}
	} else {
		return false;
	}
};
const PENDING = 'pending';
const RESOLVED = 'fullFilled';
const REJECTED = 'rejected';

const resolvePromise = (promise, x, resolve, reject) => {
	if (promise === x) {
		return reject(
			new TypeError('Chaining cycle detected for promise #<Promise>    ')
		);
	}
	if ((typeof x === 'object' && x != null) || typeof x === 'function') {
		let called;
		try {
			// 预防取.then的时候错误
			let then = x.then; // Object.definePropertype
			if (typeof then === 'function') {
				// 用then.call()为了避免在使用一次x.then报错
				then.call(
					x,
					y => {
						// resolve(y)// 采用promise的成功结果，并且向下传递
						if (called) {
							return;
						}
						called = true;
						// y有可能是一个promise，那么我们就要继续使用回调函数,直到解析出来的值是一个普通值
						resolvePromise(promise, y, resolve, reject);
					},
					r => {
						if (called) {
							return;
						}
						called = true;
						reject(r); // 采用promise的失败结果，并且向下传递
					}
				);
			} else {
				if (called) {
					return;
				}
				called = true;
				resolve(x); // x不是一个函数，是一个对象
			}
		} catch (err) {
			if (called) {
				return;
			}
			called = true;
			reject(err);
		}
	} else {
		// x是一个普通值
		resolve(x);
	}
};

class Mypromise {
	constructor(executor) {
		this.status = PENDING; //状态值
		this.success = undefined; //成功的返回值
		this.error = undefined; //失败的返回值
		this.callbackResolve = []; //成功的回调函数
		this.callbackReject = []; //失败的回调函数
		// 成功
		let resolve = success => {
			if (this.status == PENDING) {
				this.status = RESOLVED;
				this.success = success;
				this.callbackResolve.forEach(fn => fn());
			}
		};
		// 失败
		let reject = error => {
			if (this.status == PENDING) {
				this.status = REJECTED;
				this.error = error;
				this.callbackReject.forEach(fn => fn());
			}
		};
		try {
			// 执行函数
			executor(resolve, reject);
		} catch (err) {
			// 失败则直接执行reject函数
			reject(err);
		}
	}
	then(onFulFilled, onRejected) {
		onFulFilled = isFunction(onFulFilled) ? onFulFilled : data => data;
		onRejected = isFunction(onRejected)
			? onRejected
			: err => {
					throw err;
			  };
		let p = new Mypromise((resolve, reject) => {
			if (this.status == RESOLVED) {
				setTimeout(() => {
					try {
						let x = onFulFilled(this.success);
						// 添加一个resolvePromise（）的方法来判断x跟p的状态，决定p是走成功还是失败
						resolvePromise(p, x, resolve, reject);
					} catch (err) {
						// 中间任何一个环节报错都要走reject()
						reject(err);
					}
				}, 0);
			}
			if (this.status == REJECTED) {
				setTimeout(() => {
					try {
						let x = onRejected(this.error);
						resolvePromise(p, x, resolve, reject);
					} catch (err) {
						// 中间任何一个环节报错都要走reject()
						reject(err);
					}
				}, 0);
			}
			if (this.status == PENDING) {
				// 在pending状态的时候先订阅
				this.callbackResolve.push(() => {
					setTimeout(() => {
						try {
							let x = onFulFilled(this.success);
							// 添加一个resolvePromise（）的方法来判断x跟p的状态，决定p是走成功还是失败
							resolvePromise(p, x, resolve, reject);
						} catch (err) {
							// 中间任何一个环节报错都要走reject()
							reject(err);
						}
					}, 0);
				});
				this.callbackReject.push(() => {
					setTimeout(() => {
						try {
							let x = onRejected(this.error);
							resolvePromise(p, x, resolve, reject);
						} catch (err) {
							// 中间任何一个环节报错都要走reject()
							reject(err);
						}
					}, 0);
				});
			}
		});
		return p;
	}
	catch(onReJected) {
		// 返回一个没有第一个参数的then方法
		return this.then(undefined, onReJected);
	}
}

const p = new Mypromise((resolve, reject) => {
	setTimeout(function () {
		// resolve('success'); // 异步调用的时候，this.status一直是pending状态,不会执行代码了，因此要改装成发布订阅者模式
		reject('failed');
	}, 100);
});
p.then(res => {
	console.log(res);
	// return res;
})
	.then(res => {
		console.log(res);
	})
	.catch(err => {
		console.log(err, 1);
	});
